package view;

import java.util.Collection;
import java.util.TreeMap;
import engine.State;
import engine.StatemachineModel;
import model.Model;
import utils.GraphView;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.util.Callback;

/**
 * Visualization of the logic of the model.
 *
 * @author Ricardo Cruz {@literal <ricardo.pdm.cruz@gmail.com>}
 * @since  2014-11-12
 */
public class TabLogic extends Tab
{
	private CellsList cellsList;
	private StatemachineView graph;

	public TabLogic(Window window) {
		super("Logic");
		setClosable(false);

		cellsList = new CellsList();
		cellsList.setPrefHeight(0);
		graph = new StatemachineView();
		graph.setPrefWidth(350);
		TitledPane cellsBox = new TitledPane("Cells", cellsList);
		cellsBox.setCollapsible(false);
		cellsBox.setMaxHeight(Double.MAX_VALUE);

		SplitPane hsplit = new SplitPane();
		hsplit.setOrientation(Orientation.HORIZONTAL);
		hsplit.setDividerPositions(0.3f);
		hsplit.getItems().addAll(cellsBox, graph);
		SplitPane.setResizableWithParent(cellsBox, false);
		hsplit.setPadding(new Insets(6));
		setContent(hsplit);
	}

	private void showCellLogic(int cell) {
		graph.set(cell);
	}

	private static class StatemachineView extends GraphView {
		@SuppressWarnings({"rawtypes","unchecked"})
		public void set(int cell) {
			clear();
			StatemachineModel model = Model.getCellModel(cell);
			if(model != null) {
				Collection<StatemachineModel.Tuple> entries = model.getEntries();
				TreeMap<State, Node> nodes = new TreeMap<State, Node>();
				Node anyNode = addNode("\u2200", Color.YELLOW);
				for(StatemachineModel.Tuple entry: entries) {
					Node src = (entry.src != null) ? getNode(nodes, entry.src) : anyNode;
					Node dst = (entry.dst != null) ? getNode(nodes, entry.dst) : src;
					src.connectTo(entry.event.getName(), dst);
				}
			}
			layoutGraph();
		}

		private Node getNode(TreeMap<State, Node> nodes, State state) {
			if(nodes.containsKey(state))
				return nodes.get(state);
			String name = (state == null) ? "any" : state.getName();
			Node node = addNode(name, Color.WHITE);
			nodes.put(state, node);
			return node;
		}
	}

	private class CellsList extends ListView<Number> {
		public CellsList() {
			super();
			setPrefWidth(160);
			Integer cells[] = new Integer[Model.getCellTypes()];
			for(int i = 0; i < cells.length; i++)
				cells[i] = i;
			setItems(FXCollections.observableArrayList(cells));
			setCellFactory(new Callback<ListView<Number>, ListCell<Number>>() {
				public ListCell<Number> call(ListView<Number> param) {
					return new ListCell<Number>() {
						public void updateItem(Number item, boolean empty) {
							super.updateItem(item, empty);
							if (item != null) {
								int cell = item.intValue();
								HBox hbox = new HBox(6);
								hbox.setAlignment(Pos.CENTER_LEFT);
								hbox.getChildren().addAll(
									new Circle(4, Model.getCellColor(cell)),
									new Label(Model.getCellName(cell)));
								setGraphic(hbox);
							}
						}
					};
				}
			});
			getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
				public void changed(ObservableValue<? extends Number> observable,
					Number oldValue, Number value) {
						showCellLogic(value.intValue());
				}
			});
		}
	}
}
